<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>React入门 - 生命周期钩子</title>
</head>
<body> 
  <h2>虚拟DOM内部执行流程</h2>
  <ol style="color: red">
    <li>用JS对象结构来表示DOM树结构，然后用这个树结构映射成真实的DOM树，插入到文档中</li>
    <li>当状态变更时，将重新构建一棵新的对象树，然后用新的树和旧的树进行比较(使用diff算法)，记录两棵树差异</li>
    <li>将差异应用到真实的DOM树，此时便完成了更新</li>
  </ol>
  <h2>虚拟DOM原理</h2>
  <ol style="color: red">
    <li>虚拟DOM本质上就是JS和DOM之间的一个缓存，类似于CPU和硬盘，硬盘读取快慢，可通过加缓存条来解决</li>
    <li>反之，如果DOM执行速度慢，则可在JS和DOM之间加个缓存，此时JS只操作虚拟DOM，最后将变更一次性写入真实DOM</li>
  </ol>
  <h2>Diff算法</h2>
  <ol style="color: red">
    <li>如果两棵树的根元素类型不同，React将销毁旧树，创建新树</li>
    <li>如果两棵树的根元素类型相同，React会对比两者的属性是否相同，只更新不同的属性，当处理完这个节点，React将递归遍历子节点</li>
    <li>如果需要遍历插入子元素，如果没有key，React将删除子节点并重新创建，为了解决此问题，React要求为同级子节点提供key属性，此时React将根据key来匹配新树和旧树</li>
  </ol>
  <div id="container"></div>
  <script src="../../js/react.development.js"></script>
  <script src="../../js/react-dom.development.js"></script>
  <script src="../../js/babel.min.js"></script>
  <script type="text/babel">
    class MyApp extends React.Component {
      // 1. 初始化阶段
      constructor(props) {
        console.log('constructor');
        super(props);
        this.state = {
          age: 1
        };
      } 
      componentWillMount() {
        console.log('componentWillMount');
      }
      render() {
        console.log('render');
        return (
          <div>
            <span>今年{this.state.age}岁了</span>
            <button onClick={()=>ReactDOM.unmountComponentAtNode(document.getElementById('container'))}>测试卸载组件</button>
          </div>
        )
      }
      componentDidMount() {
        console.log('componentDidMount');
        this.timer = setInterval(() => {
          this.setState({
            age: this.state.age + 1
          });
        }, 1000);
      }
      // 2. 更新阶段
      componentWillUpdate() {
        console.log('componentWillUpdate');
      }
      componentDidUpdate() {
        console.log('componentDidUpdate');
      }
      // 3. 卸载阶段
      componentWillUnmount() {
        console.log('componentWillUnmount');
        clearInterval(this.timer); // 清理定时器
      }
      // 4. 出错阶段
      componentDidCatch(){
        console.log('componentDidCatch');
      }
    }
    ReactDOM.render(<MyApp/>, document.getElementById('container'));
  </script>
</body>
</html>